package main 
import (
	"fmt"
	"ffmpeg-easy-go/avcodec"
	"ffmpeg-easy-go/avformat"
	"ffmpeg-easy-go/avdevice"
	"ffmpeg-easy-go/structs"
	"ffmpeg-easy-go/avutil"
	"strconv"
)

func main() {
	fmt.Println("hello word")
	var pFormatCtx *structs.AVFormatContext 
	var ofmt_ctx *structs.AVFormatContext 
	var pCodecCtx *structs.AVCodecContext
	var pCodec *structs.AVCodec

	avformat.AvRegisterAll()
	avformat.AvformatNetworkInit()
	pFormatCtx = avformat.AvformatAllocContext()

	//var ofmt_ctx *avformat.Context
	//var ifmt_ctx *avformat.Context
	//var ovCodecCtx *avformat.CodecContext
	//var ovCodec *avformat.AvCodec
	//var video_st *avformat.Stream
	//var audio_st *avformat.Stream

	//out_path := "rtmp://127.0.0.1:1935/live/test"
	avdevice.AvdeviceRegisterAll()

	res := avformat.AvformatOpenInput(&pFormatCtx, "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov", nil,nil)

	if res < 0 {
		fmt.Println("Couldn't open  input stream.")
	}
	res = avformat.AvformatFindStreamInfo(pFormatCtx,nil)

	if res <0 {
		fmt.Println("Couldn't find stream information.")
	}

	for _, v := range pFormatCtx.Streams() {
		if v.Codec().Type() == avutil.AVMEDIA_TYPE_VIDEO {
			fmt.Println("video stream get")
			pCodecCtx = v.Codec()
			break
		}
	}
	pCodec = avcodec.AvcodecFindDecoder(pCodecCtx.GetCodecId())
	
	if pCodec == nil {
		fmt.Println("Codec not found.")
	}
	res = pCodecCtx.AvcodecOpen2(pCodec,nil)

	pFormatCtx.AvDumpFormat(0,"",0)

	avformat.AvformatAllocOutputContext2(&ofmt_ctx,nil,"flv","rtmp://localhost:1935/live/movie")
	//var ovCodec structs.AVCodec
	ovCodec := avcodec.AvcodecFindDecoderById(avcodec.AV_CODEC_ID_H264)

	if ovCodec == nil {
		fmt.Println("Can not find output video encoder")
	}
	ovCodecCtx := avcodec.AvcodecAllocContext3(ovCodec)

	if ovCodecCtx == nil {
		fmt.Println("err Context3")
	}
	ovCodecCtx.SetPixFmt("YUV420P")
	ovCodecCtx.SetWidth(pCodecCtx.Width())
	ovCodecCtx.SetHeight(pCodecCtx.Height())
	ovCodecCtx.SetTimeBaseNum(1)
	ovCodecCtx.SetTimeBaseDen(25)
	
	ovCodecCtx.SetBitRate(300000)
	ovCodecCtx.SetGopSize(250)

	ovCodecCtx.SetQMin(10)
	ovCodecCtx.SetQMax(51)
	ovCodecCtx.SetMaxBFrames(0)

	res = ovCodecCtx.AvcodecOpen2(ovCodec,nil)

	if res < 0 {
		fmt.Println("Failed to open output video encoder")
	}

	video_st := ofmt_ctx.AvformatNewStream(ovCodec)

	if video_st == nil {
		fmt.Println("new stream err")
	}

	video_st.SetTimeBaseNum(1)
	video_st.SetTimeBaseDen(30)
	video_st.SetCodec(ovCodecCtx)

	ofmt_ctx.AvDumpFormat(0,"rtmp://localhost:1935/live/movie",1)


	res = avformat.AvIOOpen(ofmt_ctx.Pb(),"rtmp://localhost:1935/live/movie",avformat.AVIO_FLAG_READ_WRITE)

	if res < 0 {
		fmt.Println("Could not open output URL")
	}
	fmt.Println("AvIOOpen成功")

	res = ofmt_ctx.AvformatWriteHeader(nil)

	if res < 0 {
		fmt.Println("Error occurred when opening output")
	}
	fmt.Println("WriteHeader成功")

	//var pFrame *structs.AVFrame

	//pFrame = avformat.AvFrameAlloc()
	var framecnt int64 = 0

	time_base_q := structs.NewAVRational(1,1000000)

	for {
		fmt.Println("开始获取数据")
		var packet *structs.AVPacket
		res = pFormatCtx.AvReadFrame(packet)
		if res < 0 {
			fmt.Println("read frame error")
		}
		fmt.Println("获取到数据")

		var got_picture int = 0
		var pFrame *structs.AVFrame
		pFrame = avformat.AvFrameAlloc()
		res = pCodecCtx.AvcodecDecodeVideo2(pFrame,&got_picture,packet)
		if res < 0 {
			fmt.Println("Decode Error")
		}

		var enc_pkt *structs.AVPacket
		avcodec.AvInitPacket(enc_pkt)
		var enc_got_frame int = 0
		res = ovCodecCtx.AvcodecEncodeVideo2(enc_pkt, pFrame,&enc_got_frame)

		if enc_got_frame == 1 {
			framecnt++
			enc_pkt.SetStreamIndex(video_st.Index())

			var time_base structs.AVRational = ofmt_ctx.Streams()[0].TimeBase()
			var r_frameratel = pFormatCtx.Streams()[0].RFrameRate()
			//1000000
			calc_float := 1000000.0 * 1.0/structs.AvQ2d(r_frameratel)
			calc_string := strconv.FormatFloat(calc_float, 'E', -1, 64)
			calc_duration, err := strconv.ParseInt(calc_string, 10, 64) 
			if err != nil {
				fmt.Println("float to int error")
			}
			enc_pkt.SetPts(structs.AvRescaleQ(framecnt*calc_duration, time_base_q, time_base))
			enc_pkt.SetDts(enc_pkt.Pts())
			enc_pkt.SetDuration(structs.AvRescaleQ(calc_duration,time_base_q,time_base))
			enc_pkt.SetPos(-1)



			

		} else {
			fmt.Println("encodec error")
		}


		
	}
}